15. The "synchronized" Keyword
The synchronized
Keyword
In this section, you will learn how to use the synchronized
keyword in Java.
ND079 JPND C2 L05 A16 Synchronized Keyword
How to Use the synchronized
Keyword
The best way to synchronize is to use high-level built-in tools like the synchronized Collections
wrappers, or data structures in the java.util.concurrent
package.
When those options aren't available, you can use the synchronized
keyword for low-level synchronization control.
Here's an example using the voting app code from the previous section:
public final class VotingApp {
private final Map<String, Integer> votes = new HashMap<>();
public void castVote(String performer) {
synchronized (this) {
Integer count = votes.get(performer);
if (count == null) {
votes.put(performer, 1);
} else {
votes.put(performer, count + 1);
}
}
}
}
The thing in parentheses after the synchronized
keyword is the lock object. When a thread enters the code block, it takes ownership of the lock. Only one thread at a time can own the lock at a time, so only one thread is allowed to be executing code inside the synchronized
block at a given time.
Lock Objects
Any object can be used as the lock. For example, you could use the votes
map as the lock object:
public void castVote(String performer) {
synchronized (votes) {
...
}
}
}
Or, you could create a completely new object just to serve the purpose of the lock:
private final Object lock = "SpecialLock";
public void castVote(String performer) {
synchronized (lock) {
...
}
}
}
If you decide to use the this
keyword, the lock object is the current instance of the class. If you're using this
to lock the entire method, you can use this trick instead:
public final class VotingApp {
private final Map<String, Integer> votes = new HashMap<>();
public synchronized void castVote(String performer) {
Integer count = votes.get(performer);
if (count == null) {
votes.put(performer, 1);
} else {
votes.put(performer, count + 1);
}
}
}
This code does the same thing, but is a little nicer to look at.
Demo: Thread-Safe Singleton Pattern
In this demo, we'll take a look at how to make the singleton design pattern thread-safe.
ND079 JPND C2 L05 A17 Demo Synchronized Keyword
Code from the Demo
import java.util.Objects;
public final class Database {
private static Database database;
private Database() {}
public static Database getInstance() {
if (database == null) {
synchronized (Database.class) {
if (database == null) {
database = new Database();
database.connect("/usr/local/data/users.db");
}
}
}
return database;
}
// Connects to the remote database.
private void connect(String url) {
Objects.requireNonNull(url);
}
public static void main(String[] args) {
Database a = Database.getInstance();
Database b = Database.getInstance();
System.out.println(a == b);
}
}